<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>贴图</title>
  <style>
    body {
      margin: 0;
      overflow: hidden;
      /* 隐藏body窗口区域滚动条 */
    }
  </style>
  <!--引入three.js三维引擎-->
  <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
  <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/controls/OrbitControls.js"></script>
  <!-- <script src="./three.js"></script> -->
  <!-- <script src="http://www.yanhuangxueyuan.com/threejs/build/three.js"></script> -->
</head>

<body>
  <script src="static/js/main.js"></script>
  <script>
    /**
     * 创建场景对象Scene
     */
    let scene = new THREE.Scene();
    
    // 平面
    let geometry = new THREE.PlaneGeometry(512, 256)
    // 立方体
    geometry = new THREE.BoxGeometry(100, 100, 100)
    // 球体
    geometry = new THREE.SphereGeometry(100, 40, 20)
    let material = new THREE.MeshLambertMaterial({
        side: THREE.DoubleSide, //两面可见
        map: new THREE.TextureLoader().load('static/img/earthmap1k.jpg')
    })
    let mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
    scene.add(mesh); //网格模型添加到场景中

    let loader = new THREE.TextureLoader()
    loader.load("static/img/earthmap1k.jpg", texture => {
        material.map = texture
        
        let mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
        mesh.position.set(0, 250, 0)
        scene.add(mesh); //网格模型添加到场景中
    })
    
    new THREE.ImageLoader().load("static/img/earthmap1k.jpg", function(img) {
      // image对象作为参数，创建一个纹理对象Texture
      let texture = new THREE.Texture(img);
      // 下次使用纹理时触发更新
      texture.needsUpdate = true;
      let material = new THREE.MeshLambertMaterial({
        map: texture, //设置纹理贴图
      })
      let mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
      mesh.position.set(250, 0, 0)
      scene.add(mesh); //网格模型添加到场景中
    })
    /*
    geometry.faceVertexUvs[0].forEach(elem => {
      elem.forEach(Vector2 => {
        // 所有的UV坐标全部设置为一个值
        // Vector2.set(0.4,0.4);
        console.log(Vector2)
      });
    })
    */
    
    // 矩形平面 设置细分数2, 2, 八个三角形组成几何体
    let geometry1 = new THREE.PlaneGeometry(204, 102, 2, 2);
    /**
     * 局部三角面显示完整纹理贴图
     */
    let t0 = new THREE.Vector2(0, 1); //图片左下角
    let t1 = new THREE.Vector2(0, 0); //图片右下角
    let t2 = new THREE.Vector2(1, 0); //图片右上角
    let t3 = new THREE.Vector2(1, 1); //图片左上角
    let uv1 = [t0, t1, t3]; //选中图片一个三角区域像素——用于映射到一个三角面
    let uv2 = [t1, t2, t3]; //选中图片一个三角区域像素——用于映射到一个三角面
    // 设置第一、第二个三角形面对应的纹理坐标
    geometry1.faceVertexUvs[0][0] = uv1
    geometry1.faceVertexUvs[0][1] = uv2
    mesh = new THREE.Mesh(geometry1, new THREE.MeshLambertMaterial({
        side: THREE.DoubleSide, //两面可见
        map: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
        // wireframe: true
    })) //网格模型对象Mesh
    mesh.position.set(250, 250, 0)
    scene.add(mesh); //网格模型添加到场景中
    
    let geometry2 = new THREE.Geometry()
    geometry2.vertices.push(new THREE.Vector3(0,0,0), new THREE.Vector3(100,0,0), new THREE.Vector3(100,50,0), new THREE.Vector3(0,50,0))
    let normal = new THREE.Vector3(0, 0, 1); //三角面法向量
    let face0 = new THREE.Face3(0, 1, 2, normal); //三角面1
    let face1 = new THREE.Face3(0, 2, 3, normal); //三角面2
    geometry2.faces.push(face0, face1); //三角面1、2添加到几何体
    let t0_ = new THREE.Vector2(0,0);//图片左下角
    let t1_ = new THREE.Vector2(1,0);//图片右下角
    let t2_ = new THREE.Vector2(1,1);//图片右上角
    let t3_ = new THREE.Vector2(0,1);//图片左上角
    uv1 = [t0_,t1_,t2_];//选中图片一个三角区域像素——映射到三角面1
    uv2 = [t0_,t2_,t3_];//选中图片一个三角区域像素——映射到三角面2
    geometry2.faceVertexUvs[0].push(uv1,uv2)
    mesh = new THREE.Mesh(geometry2, new THREE.MeshLambertMaterial({
        side: THREE.DoubleSide, //两面可见
        map: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
        //wireframe: true
    })) //网格模型对象Mesh
    mesh.position.set(250, 250, 100)
    scene.add(mesh); //网格模型添加到场景中
    
    let geometry_index = new THREE.BufferGeometry()
    vertices = new Float32Array([
        0,  0,  0, // 顶点1坐标
        100,  0,  0, // 顶点2坐标
        100, 50,  0, // 顶点3坐标
        0, 50,  0  // 顶点4坐标
    ])

    geometry_index.attributes.position = new THREE.BufferAttribute(vertices, 3)

    normals = new Float32Array([
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
    ])
    geometry_index.attributes.normal = new THREE.BufferAttribute(normals, 3)

    let index = new Uint16Array([
        0, 1, 2,
        0, 2, 3
    ])
    geometry_index.index = new THREE.BufferAttribute(index, 1)
    let uvs = new Float32Array([
        0,0, //图片左下角
        1,0, //图片右下角
        1,1, //图片右上角
        0,1, //图片左上角
    ])
    geometry_index.attributes.uv = new THREE.BufferAttribute(uvs, 2)  

    mesh = new THREE.Mesh(geometry_index, material = new THREE.MeshBasicMaterial({
        side: THREE.DoubleSide, //两面可见
        map: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
        //wireframe: true
    })); //网格模型对象Mesh
    mesh.position.set(150, 250, 100)
    scene.add(mesh); //网格模型添加到场景中
    
    let geometry3 = new THREE.BoxGeometry(100, 100, 100)
    let material_1 = new THREE.MeshPhongMaterial({
        color: 0x0033ee,
        side: THREE.DoubleSide, //两面可见
    })
    let material_2 = new THREE.MeshPhongMaterial({
        map: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
        side: THREE.DoubleSide, //两面可见
    })
    
    mesh = new THREE.Mesh(geometry3, [material_1,material_1,material_1,material_2, material_2, material_2]);    
    mesh.position.set(0, 0, 200)
    scene.add(mesh); //网格模型添加到场景中
    
    let geometry4 = new THREE.BoxGeometry(100, 100, 100)
    geometry4.faces[0].materialIndex = 1
    geometry4.faces[1].materialIndex = 1
    geometry4.faces[2].materialIndex = 1
    geometry4.faces[3].materialIndex = 1
    geometry4.faces[4].materialIndex = 1
    geometry4.faces[5].materialIndex = 1
    mesh = new THREE.Mesh(geometry4, [material_1,material_2]);    
    mesh.position.set(150, 0, 200)
    scene.add(mesh); //网格模型添加到场景中
    
    // 平面
    let geometry5 = new THREE.PlaneGeometry(512, 256)
    let texture5 = new THREE.TextureLoader().load('static/img/earthmap1k.jpg')
    texture5.wrapS = THREE.ClampToEdgeWrapping
    texture5.wrapT = THREE.ClampToEdgeWrapping
    texture5.repeat.set(4, 2)
    
    let texture6 = new THREE.TextureLoader().load('static/img/earthmap1k.jpg')
    texture6.wrapS = THREE.RepeatWrapping
    texture6.wrapT = THREE.RepeatWrapping
    texture6.repeat.set(4, 2)
    
    let texture7 = new THREE.TextureLoader().load('static/img/earthmap1k.jpg')
    texture7.wrapS = THREE.MirroredRepeatWrapping
    texture7.wrapT = THREE.MirroredRepeatWrapping
    texture7.repeat.set(4, 2)
    
    let texture8 = new THREE.TextureLoader().load('static/img/earthmap1k.jpg')
    // 偏移范围-1~1
    texture8.offset = new THREE.Vector2(0.5, 0.5)
    
    let texture9 = new THREE.TextureLoader().load('static/img/earthmap1k.jpg')
    // 设置纹理旋转角度
    texture9.rotation = Math.PI / 4
    // 设置纹理的旋转中心，默认(0,0)
    texture9.center.set(0.5,0.5);
    // console.log(texture9.matrix);
    
    mesh = new THREE.Mesh(geometry5, new THREE.MeshBasicMaterial({
        side: THREE.DoubleSide, //两面可见
        map: texture5,
        //wireframe: true
    })); //网格模型对象Mesh
    mesh.rotateX(Math.PI / 2)
    mesh.position.set(100, 100, 100)
    scene.add(mesh); //网格模型添加到场景中
    
    mesh = new THREE.Mesh(geometry5, new THREE.MeshBasicMaterial({
        side: THREE.DoubleSide, //两面可见
        map: texture6,
        //wireframe: true
    })); //网格模型对象Mesh
    mesh.rotateX(Math.PI / 2)
    mesh.position.set(200, 150, 100)
    scene.add(mesh); //网格模型添加到场景中
    
    mesh = new THREE.Mesh(geometry5, new THREE.MeshBasicMaterial({
        side: THREE.DoubleSide, //两面可见
        map: texture7,
        //wireframe: true
    })); //网格模型对象Mesh
    mesh.rotateX(Math.PI / 2)
    mesh.position.set(400, 200, 100)
    scene.add(mesh); //网格模型添加到场景中
    
    mesh = new THREE.Mesh(geometry5, new THREE.MeshBasicMaterial({
        side: THREE.DoubleSide, //两面可见
        map: texture8,
        //wireframe: true
    })); //网格模型对象Mesh
    mesh.rotateX(Math.PI / 2)
    mesh.position.set(400, 300, 100)
    scene.add(mesh); //网格模型添加到场景中
    
    mesh = new THREE.Mesh(geometry5, new THREE.MeshBasicMaterial({
        side: THREE.DoubleSide, //两面可见
        map: texture9,
        //wireframe: true
    })); //网格模型对象Mesh
    mesh.rotateX(Math.PI / 2)
    mesh.position.set(-400, 300, 100)
    scene.add(mesh); //网格模型添加到场景中
    
    
    let curve = new THREE.CatmullRomCurve3([
      new THREE.Vector3(-80, -40, 0),
      new THREE.Vector3(-70, 40, 0),
      new THREE.Vector3(70, 40, 0),
      new THREE.Vector3(80, -40, 0)
    ]);
    let tubeGeometry = new THREE.TubeGeometry(curve, 100, 6, 50, false);
    let textureLoader = new THREE.TextureLoader();
    let texture_run = textureLoader.load('static/img/run.png');
    // 设置阵列模式为 RepeatWrapping
    texture_run.wrapS = THREE.RepeatWrapping
    texture_run.wrapT=THREE.RepeatWrapping
    // 设置x方向的偏移(沿着管道路径方向)，y方向默认1
    //等价texture.repeat= new THREE.Vector2(20,1)
    texture_run.repeat.x = 20;
    let tubeMaterial = new THREE.MeshPhongMaterial({
      map: texture_run,
      transparent: true,
    });
    mesh = new THREE.Mesh(tubeGeometry, tubeMaterial); //网格模型对象Mesh
    mesh.position.set(50, 50, 200)
    scene.add(mesh); //网格模型添加到场景中
    
    let canvas = document.createElement('canvas')
    canvas.width = 512
    canvas.height = 256
    let ctx = canvas.getContext("2d")
    ctx.fillStyle = "#22ddff"
    ctx.fillRect(0, 0, 512, 256)
    ctx.beginPath()
    ctx.translate(128, 64)
    ctx.fillStyle = "#000000"
    ctx.font = "bold 48px 宋体"
    ctx.textBaseline = "middle"
    ctx.textAlign = "center"
    ctx.fillText("Canvas 纹理", 0, 0)
    
    let canvasTexture = texture = new THREE.CanvasTexture(canvas);
    
    let image = new Image();
    image.src = "static/img/run.png";
    image.onload = function() {
        ctx.drawImage(image, 128, 64, 128, 64);
        // 注意图片加载完成执行canvas相关方法后，要更新一下纹理
        canvasTexture.needsUpdate = true;
    }
    
    let canvasGeometry = new THREE.PlaneGeometry(128, 64);
    mesh = new THREE.Mesh(canvasGeometry, new THREE.MeshPhongMaterial({
      map: canvasTexture, // 设置纹理贴图
    }))
    mesh.position.set(50, 50, 300)
    scene.add(mesh); //网格模型添加到场景中
    
    let video = document.createElement("video")
    video.src = "static/video/mov_bbb.mp4"
    video.muted = true
    video.autoplay = "autoplay"
    
    let videoTexture = new THREE.VideoTexture(video)
    let videoGeometry = new THREE.PlaneGeometry(128, 64);
    mesh = new THREE.Mesh(videoGeometry, new THREE.MeshPhongMaterial({
      map: videoTexture, // 设置纹理贴图
    }))
    mesh.position.set(200, 50, 300)
    scene.add(mesh); //网格模型添加到场景中
    
    
    let geometry_nt = new THREE.BoxGeometry(100, 100, 100)
    let material_nt = new THREE.MeshPhongMaterial({
        normalMap: new THREE.TextureLoader().load('static/img/normal3_256.jpg'),
        //设置深浅程度，默认值(1,1)。
        normalScale: new THREE.Vector2(3, 3),
        side: THREE.DoubleSide, //两面可见
    })
    
    mesh = new THREE.Mesh(geometry_nt, material_nt);    
    mesh.position.set(150, 0, 200)
    scene.add(mesh); //网格模型添加到场景中
    
    
    let geometry_er = new THREE.SphereGeometry(100, 40, 20)
    mesh = new THREE.Mesh(geometry_er, new THREE.MeshPhongMaterial({
        side: THREE.DoubleSide, //两面可见
        map: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
        normalMap: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
        //设置深浅程度，默认值(1,1)。
        normalScale: new THREE.Vector2(-3, -3),
    })); //网格模型对象Mesh   
    mesh.position.set(450, 0, 0)
    scene.add(mesh); //网格模型添加到场景中
    
    mesh = new THREE.Mesh(geometry_er, new THREE.MeshPhongMaterial({
        side: THREE.DoubleSide, //两面可见
        map: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
        bumpMap: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
        //设置凹凸高度，默认值1
        bumpScale: 3,
    })); //网格模型对象Mesh   
    mesh.position.set(450, 0, 200)
    scene.add(mesh); //网格模型添加到场景中
    
    mesh = new THREE.Mesh(geometry_er, new THREE.MeshPhongMaterial({
        side: THREE.DoubleSide, //两面可见
        map: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
        // 高光部分的亮度，默认30
        shininess: 30,
        // 高光贴图
        specularMap: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
    })); //网格模型对象Mesh   
    mesh.position.set(450, -200, 200)
    scene.add(mesh); //网格模型添加到场景中
    
    let geometry_lm = new THREE.PlaneGeometry(256, 512)
    geometry_lm.faceVertexUvs[1] = geometry_lm.faceVertexUvs[0]
    mesh = new THREE.Mesh(geometry_lm, new THREE.MeshLambertMaterial({
        color: 0x999999,
        side: THREE.DoubleSide, //两面可见
        // 设置光照贴图
        lightMap: new THREE.TextureLoader().load('static/img/earthmap1k.jpg'),
        // 烘培光照的强度. 默认 1
        ightMapIntensity:0.5,
    })); //网格模型对象Mesh
    mesh.rotateX(-Math.PI / 2)
    mesh.position.set(0, -100, 0)
    scene.add(mesh); //网格模型添加到场景中
    
    let geometry_env = new THREE.BoxGeometry(100, 100, 100)
    loader = new THREE.CubeTextureLoader()
    loader.setPath("static/img/skybox/")
    let CubeTexture = loader.load(['top.jpg', 'bottom.jpg', 'left.jpg', 'right.jpg', 'front.jpg', 'back.jpg'])
    mesh = new THREE.Mesh(geometry_env, new THREE.MeshPhongMaterial({
        side: THREE.DoubleSide, //两面可见
        //网格模型设置颜色，网格模型颜色和环境贴图会进行融合计算
        // color:0xff0000,
        envMap: CubeTexture, //设置环境贴图
        // 环境贴图反射率   控制环境贴图对被渲染三维模型影响程度
        reflectivity: 0.9,
    })); //网格模型对象Mesh
    mesh.position.set(-100, -100, 0)
    scene.add(mesh); //网格模型添加到场景中
    
    let width_t =32, height_t = 32
    let size = width_t * height_t
    let data = new Uint8Array(size * 4)
    for (let i = 0; i < size * 4; i += 4) {
        data[i] = 255 * Math.random()
        data[i + 1] = 255 * Math.random()
        data[i + 2] = 255 * Math.random()
        data[i + 3] = 255 * 0.6
    }
    let geometry_data = new THREE.BoxGeometry(100, 100, 100)
    let texture_data = new THREE.DataTexture(data, width_t, height_t, THREE.RGBAFormat)
    texture_data.needsUpdate = true
    mesh = new THREE.Mesh(geometry_data, new THREE.MeshPhongMaterial({
        side: THREE.DoubleSide, //两面可见
        map: texture_data,
        transparent: true,
    })); //网格模型对象Mesh
    mesh.position.set(100, -200, 0)
    scene.add(mesh); //网格模型添加到场景中
    
    mesh = genMesh({
        geometry: new THREE.PlaneGeometry(100, 100), 
        material: new THREE.MeshPhongMaterial({
            side: THREE.DoubleSide, //两面可见
            map: texture_data,
            transparent: true,
        }),
        callback: opt => {
            let geometry = opt['geometry']
            return new THREE.Mesh(geometry, new THREE.MeshPhongMaterial({
                color: 0xaaccdd,
                side: THREE.DoubleSide, //两面可见
            }))
        }
        })
    mesh.position.set(-100, -200, 0)
    scene.add(mesh); //网格模型添加到场景中
    
    let axisHelper = new THREE.AxesHelper(250);
    scene.add(axisHelper);
    /**
     * 光源设置
     */
    //点光源
    let point = new THREE.PointLight(0xffffff);
    point.position.set(400, 200, 300); //点光源位置
    scene.add(point); //点光源添加到场景中
    //环境光
    let ambient = new THREE.AmbientLight(0x888888);
    scene.add(ambient);
    // console.log(scene)
    // console.log(scene.children)
    /**
     * 相机设置
     */
    let width = window.innerWidth; //窗口宽度
    let height = window.innerHeight; //窗口高度
    let k = width / height; //窗口宽高比
    let s = 200; //三维场景显示范围控制系数，系数越大，显示的范围越大
    //创建相机对象
    let camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
    camera.position.set(0, 200, 600); //设置相机位置
    camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
    /**
     * 创建渲染器对象
     */
    let renderer = new THREE.WebGLRenderer();
    renderer.setSize(width, height);//设置渲染区域尺寸
    renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
    document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
    
    Game = {
		tickLength: 16, 				// 20Hz
		lastTick: performance.now(),	// 最后更新时间
		stopKey: 0,
		canvas: null,
		context: null,
	}
    function render(tFrame) {
        if (tFrame === undefined) {
            tFrame = performance.now()
            Game.lastTick = performance.now()
        }
        let nextTick = Game.lastTick + Game.tickLength
        let tickNum = 0
        if (tFrame > nextTick) {
            tickNum = Math.floor((tFrame - Game.lastTick) / Game.tickLength)
        }
        Game.lastTick = tFrame
        /*
        for (let num = 0; num < tickNum; ++num) {
            for (let i = 0, l = meshes.length; i < l; ++i) {
                meshes[i].position.set((i + 0.5 - l / 2) * 150, 0, 0)
                meshes[i].rotateY(3.14 / 180)
            }
        }
        */
        texture_run.offset.x -= 0.001
        //执行渲染操作   指定场景、相机作为参数
        renderer.render(scene, camera);
        Game.stopKey = requestAnimationFrame(render)
    }
    render()
    let controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象
    controls.addEventListener('change', render);
  </script>
</body>
</html>
